package bo.edu.umss.jaba.interpreter;
 
import bo.edu.umss.jaba.node.* ;
import bo.edu.umss.jaba.analysis.* ;
import bo.edu.umss.jaba.hashtable.*;
import java.lang.System;
import java.io.*;

import java.util.List;
import java.util.LinkedList;
import java.util.Iterator;
import java.util.ListIterator;

 
public class Interpreter extends DepthFirstAdapter {

	//List hash;
	List lista_metodos;

	PrintWriter pw;
	String filename;
	FileWriter f;
	int cnt_cond = 0;
	int cnt_ciclo = 0;

	public Interpreter (List h, String fn)
	{
		lista_metodos = h;
		filename = fn;
		pw = null;
		f = null;

		try
		{	
			f = new FileWriter (filename + ".ssm");
			pw = new PrintWriter(f);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	
		//lista_metodos.get

		//anadir_archivo ("link " + hash.size());
	}

	public void cerrar_fichero ()
	{
		anadir_archivo ("unlink");
			try
			{
				if(f != null)
					f.close();
			}catch (Exception e)
			{
				e.printStackTrace();
			}

	}	
	private int obtener_posicion (String identificador, String method_name)
	{
		if(lista_metodos != null)			
		for (int i=0; i < lista_metodos.size(); i++)
		{
			ListOfSymbols los = (ListOfSymbols) lista_metodos.get (i);
			if (los.getName().equals (method_name))
			{
				int pos = los.symbols.indexOf(identificador);
				if (pos == -1)
					System.out.println ("Error: No se encontro el simbolo");
				return pos;
			}

		}

		System.out.println ("Error: No se encontro el metodo o simbolo");
		return -1;
	}

	private int obtener_tamano_var (String method_name)
	{
		if(lista_metodos != null)			
		for (int i=0; i < lista_metodos.size(); i++)
		{
			ListOfSymbols los = (ListOfSymbols) lista_metodos.get (i);
			if (los.getName().equals (method_name))
			{
				return los.symbols.size();
			}

		}

		System.out.println ("Error: No se pudo obtener tamano de lista");
		return -1;

	}

	private void anadir_archivo (String linea)
	{
		System.out.println (linea);
		try
		{
			pw.println ("	" + linea);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

	}

	private void f_expresion (Object expresion, String method_name)
	{
		if(expresion instanceof AEnteroExpresion)
		{
			AEnteroExpresion entero = (AEnteroExpresion) expresion;
			int num = Integer.parseInt(entero.getEntero().getText());
			anadir_archivo ("ldc " + num);
		}

		if(expresion instanceof ALogicoExpresion)
		{
			ALogicoExpresion logico = (ALogicoExpresion) expresion;
			int valor = 0;
			if (logico.getLogico() instanceof AVerdaderoLogico)
				valor = 1;
			else 
			if (logico.getLogico() instanceof AFalsoLogico)
				valor = 0;

			anadir_archivo ("ldc " + valor);
		}

		if(expresion instanceof AIdentificadorExpresion)
		{
			AIdentificadorExpresion identificador = (AIdentificadorExpresion) expresion;

			int pos2 = obtener_posicion (identificador.getIdentificador().getText(), method_name);
			anadir_archivo ("ldl " + pos2);
		}	

		if(expresion instanceof AOperadorExpresion)
		{
			AOperadorExpresion opexpresion = (AOperadorExpresion) expresion;
			f_expresion (opexpresion.getEi(), method_name);
			f_expresion (opexpresion.getEd(), method_name);
			Object operador = opexpresion.getOp();

			if (operador instanceof AMenorqueOp)
				anadir_archivo ("lt");
			if (operador instanceof AMayorqueOp)
				anadir_archivo ("gt");
			if (operador instanceof AMenorigualOp)
				anadir_archivo ("le");
			if (operador instanceof AMayorigualOp)
				anadir_archivo ("ge");
			if (operador instanceof AIgualOp)
				anadir_archivo ("eq");
			if (operador instanceof ADistintoOp)
				anadir_archivo ("ne");
			if (operador instanceof AMasOp)
				anadir_archivo ("add");
			if (operador instanceof AMenosOp)
				anadir_archivo ("sub");
			if (operador instanceof AMultOp)
				anadir_archivo ("mul");
			if (operador instanceof ADivOp)
				anadir_archivo ("div");

		}


	}

	private void procesar_parametros (Object pparam, String method_name)
	{
		if(pparam instanceof AParamnParamExp)
		{
			AParamnParamExp paramexp = (AParamnParamExp) pparam;
			f_expresion(paramexp.getExpresion(), method_name);
			procesar_parametros(paramexp.getParamExp(), method_name);
		}


		if(pparam instanceof AParam1ParamExp)
		{
			AParam1ParamExp paramexp = (AParam1ParamExp) pparam;
			f_expresion(paramexp.getExpresion(), method_name);

		}

	}	

	private void procesar_bloque (Object b_test, String method_name)
	{
		AConsBloque bloque = null;

		if (b_test == null)
		{
			return;
		}

		if (b_test instanceof ANilBloque)
			return;

		if (b_test instanceof AConsBloque)
			bloque = (AConsBloque) b_test;
		else
			return;

		Object instruccion = bloque.getInstruccion();

		System.out.println ("ins:" + instruccion.toString());

		if(instruccion instanceof AAsignacionInstruccion)
		{
			AAsignacionInstruccion ainstruccion = (AAsignacionInstruccion) instruccion;
			int pos = obtener_posicion (ainstruccion.getIdentificador().getText(), method_name);

			Object expresion = ainstruccion.getExpresion();
			f_expresion (expresion, method_name);
			anadir_archivo ("stl " + pos);
		}

		if(instruccion instanceof AAsigmetInstruccion)
		{
			AAsigmetInstruccion metodo_i = (AAsigmetInstruccion) instruccion;

			procesar_parametros (metodo_i.getParamExp(), method_name);

			String imethod_name = metodo_i.getNmetodo().getText();
			anadir_archivo ("bsr " + imethod_name);

		}

		if(instruccion instanceof AMostrarInstruccion)
		{
			AMostrarInstruccion mostrar_i = (AMostrarInstruccion) instruccion;
			int pos = obtener_posicion (mostrar_i.getIdentificador().getText(), method_name);
			anadir_archivo ("ldl " + pos); 
			anadir_archivo ("trap 0"); 
		}
		if(instruccion instanceof ACicloInstruccion)
		{
			int val_cond = cnt_ciclo;
			cnt_ciclo++;

			ACicloInstruccion cicloi = (ACicloInstruccion) instruccion;

			anadir_archivo ("ini_mientras_" + val_cond + ":");

			f_expresion (cicloi.getCondicion(), method_name);
			anadir_archivo ("ldc 0");
			anadir_archivo ("ne");
			anadir_archivo ("brf fin_mientras_" + val_cond);
			//anadir_archivo ("ini_mientras_" + val_cond + ":");

			//AProgramaPrograma n = new AProgramaPrograma ();
			//n.setBloque (cicloi.getBloque());
			//caseAProgramaPrograma (n);

			procesar_bloque (cicloi.getBloque(), method_name);

			anadir_archivo ("bra ini_mientras_" + val_cond);
			anadir_archivo ("fin_mientras_" + val_cond + ":");
			



		}
		if(instruccion instanceof ACondicionalInstruccion)
		{
			ACondicionalInstruccion condicionali = (ACondicionalInstruccion) instruccion;
			f_expresion (condicionali.getCondicion(), method_name);

			int val_else = cnt_cond;
			cnt_cond++;

			anadir_archivo ("ldc 0");
			anadir_archivo ("ne");
			anadir_archivo ("brf si_no_" + val_else);
	

			//AProgramaPrograma n = new AProgramaPrograma ();
			//n.setBloque (condicionali.getBthen());
			//caseAProgramaPrograma (n);
			procesar_bloque (condicionali.getBthen(), method_name);

			anadir_archivo ("bra fin_si_" + val_else);
			anadir_archivo ("si_no_" + val_else + ":");

			//n.setBloque (condicionali.getBelse());
			//caseAProgramaPrograma (n);
			procesar_bloque (condicionali.getBelse(), method_name);

			anadir_archivo ("fin_si_" + val_else + ":");
				

		}

		if(bloque.getBloque() instanceof AConsBloque)
		{
			//node.setBloque(bloque.getBloque());
			//caseAProgramaPrograma (node);
			procesar_bloque (bloque.getBloque(), method_name);
		}

	}

	public void caseAMetodoMetodo (AMetodoMetodo node)
	{
		//System.out.println ("metodo: " + node.getIdentificador().getText());

		String method_name = node.getIdentificador().getText();

		Object b_test = node.getBloque();

		anadir_archivo (method_name + ":");

		anadir_archivo ("link " + obtener_tamano_var (method_name));

		procesar_bloque (b_test, method_name);

		if(node.getMetodo() instanceof AMetodoMetodo)
		{
			caseAMetodoMetodo ((AMetodoMetodo)node.getMetodo());
		}
	}


	public void caseAProgramaPrograma (AProgramaPrograma node)
	{
		anadir_archivo ("bra main");

		if (node.getMetodo() instanceof AMetodoMetodo)
			caseAMetodoMetodo ((AMetodoMetodo) node.getMetodo());


		Object b_test = node.getBloque();

	
		anadir_archivo ("main:");

		anadir_archivo ("link " + obtener_tamano_var ("main"));

		procesar_bloque (b_test, "main");
	}




} 
